Binding fidelity: a collection a loop iterates reads as unused - #508
Merged
Conversation
A forEach loop names the collection it iterates, and that name is the one place the collection is read. Binding fidelity now records it as a consumption site, so a technique output reaching a loop and nothing else is live rather than dead. The name resolves against its head, because a loop iterates a field of a produced object as often as the object itself. The corpus reports the same seventy findings before and after, all triaged, so the change adds sight rather than findings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A check that measures whether a declared value is ever used has to know every way a value can be used. This one knew several and not the one a loop uses, so a value produced for a loop to iterate read as unused.
What happens today
The binding-fidelity guard reports a declared output that nothing consumes, which is how a technique that produces a value nobody wants gets noticed. To do that it collects every site where a name is consumed: a
{token}read in prose, a variable named by a gate expression, a value or remap passed at a step binding, and an input of the same name declared by another technique — the convention by which one operation's output chains into the next one's input.A loop is missing from that list. When an activity iterates a collection, it names that collection once, in the loop's
over. That is the only place the collection is read, and the guard does not look there. A technique whose output exists to be iterated therefore reports as dead.The corpus does not currently show this, and the reason is incidental rather than structural. The collections it iterates — the open assumptions, the plan's tasks — happen to be declared as an input by some other technique as well, so the name-match convention rescues them. A collection that is only ever iterated has nothing to rescue it.
The fix
The loop's
overjoins the consumption sites. A collection reaching a loop and nothing else is live.The name resolves against its head, the same way a
{token}read does, because a loop iterates a field of a produced object about as often as it iterates the object itself —implementation_plan.tasksis produced asimplementation_plan. Without that, three existing loops in the corpus would have been reported as reading something nothing produces. That is not a hypothetical: the first version of this change produced exactly those three, which is how the head rule earned its place.Verification
Against the unchanged corpus the guard reports the same 70 findings before and after, all triaged, none live, none untriaged. The change adds sight rather than findings.
Against a branch that adds a technique producing a collection for a loop, the finding it previously raised is gone.
Typecheck is clean and the full suite is green at 1097 passed, 2 skipped, 0 failed.
Scope
The consumption set, and the head resolution that makes it correct for a dotted collection.
Acceptance criteria
overcollection is live.Non-goals
This does not change the other three checks the guard makes, and does not change which findings are triaged.
This does not address the scope question in #491 finding 1 — that bindings are verified against the workflow that authored a technique rather than the one running it. That is a separate defect in the same guard and is not touched here.